package com.apobates.forum.toro.tuple.strategy;

import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 抽像的Many Triple 异步策略
 * @param <L> 左对象类型
 * @param <M> 中对象类型
 * @param <R> 右对象类型
 * @param <E> 中对象查询函数参数的类型
 * @param <U> 右对象查询函数参数的类型
 *
 * @author xiaofanku@live.cn
 * @since 20220517
 */
public class AbstractManyTripleFutureStrategy<L,M,R,E,U> extends AbstractTupleStrategy {
    private final int timeout;
    private final TimeUnit unit;
    private final static Logger logger = LoggerFactory.getLogger(AbstractManyTripleFutureStrategy.class);

    public AbstractManyTripleFutureStrategy(int timeout, TimeUnit unit) {
        this.timeout = timeout;
        this.unit = unit;
    }

    public AbstractManyTripleFutureStrategy() {
        this(1, TimeUnit.SECONDS);
    }

    public int getTimeout() {
        return timeout;
    }

    public TimeUnit getUnit() {
        return unit;
    }

    /**
     * 返回聚合结果
     * @param lFuture 左对象的Future实例
     * @param middleFun 中对象查询函数
     * @param rightFun 右对象查询函数
     * @param argumentMap 连接参数集合
     * @return
     */
    protected Collection<Triple<L, M, R>> get(
            CompletableFuture<Collection<L>> lFuture,
            Function<Collection<E>, Collection<M>> middleFun,
            Function<Collection<U>, Collection<R>> rightFun,
            Map<String, String> argumentMap) {
        // 左右
        CompletableFuture<Pair<Collection<L>, Collection<R>>> lrPairFuture = lFuture.thenCompose((Collection<L> leftObjSet) -> CompletableFuture.supplyAsync(() -> {
            // 取得右对象的查询参数
            Set<U> rightArgs = leftObjSet.stream().map(ele -> {
                Object selectRightVal = getBaseSelectVal(ele, argumentMap.get("rightAttr"), argumentMap.get("rightAttrType"), "右");
                try {
                    return (U) selectRightVal;
                }catch (Exception e){
                    logger.debug(String.format("[TS][ManyTriple]右函数的查询参数时出现异常:%s", e.getMessage()));
                    return null;
                }
            }).filter(Objects::nonNull).collect(Collectors.toSet());
            Collection<R> rightObjSet = rightFun.apply(rightArgs);
            return Pair.of(leftObjSet, rightObjSet);
        })).completeOnTimeout(null, this.timeout, this.unit);
        // 中
        CompletableFuture<Collection<M>> middleFuture = lFuture.thenCompose((Collection<L> leftObjSet) -> CompletableFuture.supplyAsync(() -> {
            // 取得中对象的查询参数
            Set<E> middleArgs = leftObjSet.stream().map(ele -> {
                Object selectMiddleArg = getBaseSelectVal(ele, argumentMap.get("middleAttr"), argumentMap.get("middleAttrType"), "中");
                try {
                    return (E) selectMiddleArg;
                }catch (Exception e){
                    logger.debug(String.format("[TS][ManyTriple]中函数的查询参数时出现异常:%s", e.getMessage()));
                    return null;
                }
            }).filter(Objects::nonNull).collect(Collectors.toSet());
            return middleFun.apply(middleArgs);
        })).completeOnTimeout(null, this.timeout, this.unit);
        // 折叠
        return lrPairFuture.thenCombine(middleFuture, (Pair<Collection<L>, Collection<R>> lr, Collection<M> ms) -> {
            return foldTriple(lr.getLeft(), ms, lr.getRight(), argumentMap);
        }).completeOnTimeout(Collections.emptyList(), this.timeout, this.unit).orTimeout(this.timeout, this.unit).join();
    }

    @Override
    protected String getSentinel() {
        return "ManyTriple";
    }
}
